#pragma once

#include "TypeInfo.h"
#include "Helpers.h"
#include <string>

namespace MockItNow
{
	class ArgumentRecordInterface
	{
	public:

		virtual ~ArgumentRecordInterface() {}

		virtual std::string GetTypeName() const = 0;

		virtual void IgnoreArgument() = 0;
		virtual std::string Evaluate() const = 0;
	};

	template<typename T, typename C>
	class ArgumentRecord : public ArgumentRecordInterface
	{
	public:
	
		ArgumentRecord(C compareFunction)
		: m_recordArgument(0),
		  m_replayArgument(0),
		  m_compareFunction(compareFunction)
		{
			MOCKITNOW_STATIC_ASSERT(IsReference<T>::Value == false, ArgumentArgumentTypeCannotBeReference);
			MOCKITNOW_STATIC_ASSERT(IsConst<T>::Value == false, ArgumentArgumentTypeCannotBeConst);
		}

		virtual ~ArgumentRecord()
		{
			delete m_replayArgument;
			delete m_recordArgument;
		}

		virtual std::string GetTypeName() const
		{
			return GetFriendlyTypeName<T>();
		}

		virtual void IgnoreArgument()
		{
			m_compareFunction = 0;
		}

		virtual std::string Evaluate() const
		{
			if (m_compareFunction == 0)
				return "";

			if (m_recordArgument == 0)
				return "Argument was never recorded";

			if (m_replayArgument == 0)
				return "Argument was never replayed";

			return m_compareFunction(*m_recordArgument, *m_replayArgument);
		}

		void RecordArgument(const T& argument)
		{
			m_recordArgument = new Storage<T>(argument);
		}

		void ReplayArgument(const T& argument)
		{
			m_replayArgument = new Storage<T>(argument);
		}

		void SetCompareFunction(C compareFunction)
		{
			m_compareFunction = compareFunction;
		}

	private:

		Storage<T>* m_recordArgument;
		Storage<T>* m_replayArgument;

		C m_compareFunction;
	};
}
